\unset ECHO\i test/setup.sqlSELECT plan(372);
SET client_min_messages = warning;
CREATE SCHEMA ha;
CREATE TABLE ha.sometab(id INT);
CREATE SEQUENCE ha.someseq;
CREATE SCHEMA "LOL";
CREATE TABLE "LOL"."ATable"("AColumn" INT);
CREATE SEQUENCE "LOL"."ASeq";
CREATE OR REPLACE FUNCTION set_search_path() returns setof text as $$BEGIN    IF pg_version_num() < 80200 THEN        EXECUTE 'SET search_path = ha, "LOL", '             || regexp_replace(current_setting('search_path'), '[$][^,]+,', '')             || ', pg_catalog';
        RETURN;
    ELSE        EXECUTE 'SET search_path = ha, "LOL", ' || current_setting('search_path') || ', pg_catalog';
    END IF;
END;
$$ language plpgsql;
SELECT * FROM set_search_path();
RESET client_min_messages;
SELECT * FROM check_test(    table_privs_are( 'ha', 'sometab', current_user, _table_privs(), 'whatever' ),    true,    'table_privs_are(sch, tab, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    table_privs_are( 'LOL', 'ATable', current_user, _table_privs(), 'whatever' ),    true,    'table_privs_are(LOL, ATable, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    table_privs_are( 'ha', 'sometab', current_user, _table_privs() ),    true,    'table_privs_are(sch, tab, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(_table_privs(), ', ') || ' on table ha.sometab' ,    '');
SELECT * FROM check_test(    table_privs_are( 'LOL', 'ATable', current_user, _table_privs() ),    true,    'table_privs_are(LOL, ATable, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(_table_privs(), ', ') || ' on table "LOL"."ATable"' ,    '');
SELECT * FROM check_test(    table_privs_are( 'sometab', current_user, _table_privs(), 'whatever' ),    true,    'table_privs_are(tab, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    table_privs_are( 'ATable', current_user, _table_privs(), 'whatever' ),    true,    'table_privs_are(ATable, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    table_privs_are( 'sometab', current_user, _table_privs() ),    true,    'table_privs_are(tab, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(_table_privs(), ', ') || ' on table sometab' ,    '');
SELECT * FROM check_test(    table_privs_are( 'ATable', current_user, _table_privs() ),    true,    'table_privs_are(ATable, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(_table_privs(), ', ') || ' on table "ATable"' ,    '');
CREATE OR REPLACE FUNCTION run_extra_fails() RETURNS SETOF TEXT LANGUAGE plpgsql AS $$DECLARE    allowed_privs TEXT[];
    test_privs    TEXT[] := '{}';
    missing_privs TEXT[] := '{}';
    tap           record;
    last_index    INTEGER;
BEGIN        allowed_privs := _table_privs();
    last_index    := array_upper(allowed_privs, 1);
    FOR i IN 1..last_index - 2 LOOP        test_privs := test_privs || allowed_privs[i];
    END LOOP;
    FOR i IN last_index - 1..last_index LOOP        missing_privs := missing_privs || allowed_privs[i];
    END LOOP;
    FOR tap IN SELECT * FROM check_test(        table_privs_are( 'ha', 'sometab', current_user, test_privs, 'whatever' ),            false,            'table_privs_are(sch, tab, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')    ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    FOR tap IN SELECT * FROM check_test(            table_privs_are( 'sometab', current_user, test_privs, 'whatever' ),            false,            'table_privs_are(tab, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')    ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
END;
$$;
SELECT * FROM run_extra_fails();
CREATE USER __someone_else;
SELECT * FROM check_test(    table_privs_are( 'ha', 'sometab', '__someone_else', _table_privs(), 'whatever' ),    false,    'table_privs_are(sch, tab, other, privs, desc)',    'whatever',    '    Missing privileges:        ' || array_to_string(_table_privs(), E'\n        '));
GRANT SELECT, INSERT, UPDATE, DELETE ON ha.sometab TO __someone_else;
SELECT * FROM check_test(    table_privs_are( 'ha', 'sometab', '__someone_else', ARRAY[        'SELECT', 'INSERT', 'UPDATE', 'DELETE'    ], 'whatever'),    true,    'table_privs_are(sch, tab, other, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    table_privs_are( 'ha', 'nonesuch', current_user, _table_privs(), 'whatever' ),    false,    'table_privs_are(sch, tab, role, privs, desc)',    'whatever',    '    Table ha.nonesuch does not exist');
SELECT * FROM check_test(    table_privs_are( 'ha', 'sometab', '__nonesuch', _table_privs(), 'whatever' ),    false,    'table_privs_are(sch, tab, role, privs, desc)',    'whatever',    '    Role __nonesuch does not exist');
SELECT * FROM check_test(    table_privs_are( 'ha', 'sometab', '__nonesuch', '{}'::text[] ),    false,    'table_privs_are(sch, tab, role, no privs)',    'Role __nonesuch should be granted no privileges on table ha.sometab' ,    '    Role __nonesuch does not exist');
SELECT * FROM check_test(    table_privs_are( 'sometab', '__nonesuch', '{}'::text[] ),    false,    'table_privs_are(tab, role, no privs)',    'Role __nonesuch should be granted no privileges on table sometab' ,    '    Role __nonesuch does not exist');
SELECT * FROM check_test(    database_privs_are( current_database(), current_user, _db_privs(), 'whatever' ),    true,    'database_privs_are(db, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    database_privs_are( current_database(), current_user, _db_privs() ),    true,    'database_privs_are(db, role, privs, desc)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(_db_privs(), ', ') || ' on database ' || quote_ident( current_database() ),    '');
SELECT * FROM check_test(    database_privs_are( '__nonesuch', current_user, _db_privs(), 'whatever' ),    false,    'database_privs_are(non-db, role, privs, desc)',    'whatever',    '    Database __nonesuch does not exist');
SELECT * FROM check_test(    database_privs_are( current_database(), '__noone', _db_privs(), 'whatever' ),    false,    'database_privs_are(db, non-role, privs, desc)',    'whatever',    '    Role __noone does not exist');
SELECT * FROM check_test(    database_privs_are( current_database(), '__someone_else', _db_privs(), 'whatever' ),    false,    'database_privs_are(db, ungranted, privs, desc)',    'whatever',    '    Missing privileges:        CREATE');
SELECT * FROM check_test(    database_privs_are(        current_database(), current_user,        CASE WHEN pg_version_num() < 80200 THEN ARRAY['CREATE'] ELSE ARRAY['CREATE', 'CONNECT'] END,        'whatever'    ),    false,    'database_privs_are(db, ungranted, privs, desc)',    'whatever',    '    Extra privileges:        TEMPORARY');
SELECT * FROM check_test(    database_privs_are( current_database(), '__noone', '{}'::text[] ),    false,    'database_privs_are(db, non-role, no privs)',    'Role __noone should be granted no privileges on database ' || quote_ident( current_database() ),    '    Role __noone does not exist');
CREATE OR REPLACE FUNCTION public.foo(int, text) RETURNS VOID LANGUAGE SQL AS '';
CREATE OR REPLACE FUNCTION "LOL"."DoIt"(int, text) RETURNS VOID LANGUAGE SQL AS '';
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    true,    'function_privs_are(sch, func, args, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    function_privs_are(        'LOL', 'DoIt', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    true,    'function_privs_are(LOL, DoIt, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE']    ),    true,    'function_privs_are(sch, func, args, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function public.foo(integer, text)'    '');
SELECT * FROM check_test(    function_privs_are(        'LOL', 'DoIt', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE']    ),    true,    'function_privs_are(LOL, DoIt, args, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function "LOL"."DoIt"(integer, text)'    '');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    true,    'function_privs_are(func, args, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    function_privs_are(        'DoIt', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    true,    'function_privs_are(DoIt, args, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE']    ),    true,    'function_privs_are(func, args, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function foo(integer, text)'    '');
SELECT * FROM check_test(    function_privs_are(        'DoIt', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE']    ),    true,    'function_privs_are(DoIt, args, role, privs)',    'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function "DoIt"(integer, text)'    '');
SELECT * FROM check_test(    function_privs_are(        'public', '__nonesuch', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    false,    'function_privs_are(sch, non-func, args, role, privs, desc)',    'whatever',    '    Function public.__nonesuch(integer, text) does not exist');
SELECT * FROM check_test(    function_privs_are(        '__nonesuch', ARRAY['integer', 'text'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    false,    'function_privs_are(non-func, args, role, privs, desc)',    'whatever',    '    Function __nonesuch(integer, text) does not exist');
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        '__noone', ARRAY['EXECUTE'], 'whatever'    ),    false,    'function_privs_are(sch, func, args, noone, privs, desc)',    'whatever',    '    Role __noone does not exist');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        '__noone', ARRAY['EXECUTE'], 'whatever'    ),    false,    'function_privs_are(func, args, noone, privs, desc)',    'whatever',    '    Role __noone does not exist');
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        '__someone_else', ARRAY['EXECUTE'], 'whatever'    ),    true,    'function_privs_are(sch, func, args, other, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        '__someone_else', ARRAY['EXECUTE'], 'whatever'    ),    true,    'function_privs_are(func, args, other, privs, desc)',    'whatever',    '');
REVOKE EXECUTE ON FUNCTION public.foo(int, text) FROM PUBLIC;
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        '__someone_else', ARRAY['EXECUTE'], 'whatever'    ),    false,    'function_privs_are(sch, func, args, unpriv, privs, desc)',    'whatever',    '    Missing privileges:        EXECUTE');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        '__someone_else', ARRAY['EXECUTE'], 'whatever'    ),    false,    'function_privs_are(func, args, unpriv, privs, desc)',    'whatever',    '    Missing privileges:        EXECUTE');
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        '__someone_else', '{}'::text[], 'whatever'    ),    true,    'function_privs_are(sch, func, args, unpriv, empty, desc)',    'whatever',    '');
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        '__someone_else', '{}'::text[]    ),    true,    'function_privs_are(sch, func, args, unpriv, empty)',    'Role __someone_else should be granted no privileges on function public.foo(integer, text)'    '');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        '__someone_else', '{}'::text[]    ),    true,    'function_privs_are(func, args, unpriv, empty)',    'Role __someone_else should be granted no privileges on function foo(integer, text)'    '');
SELECT * FROM check_test(    function_privs_are(        'public', 'foo', ARRAY['integer', 'text'],        current_user, '{}'::text[], 'whatever'    ),    false,    'function_privs_are(sch, func, args, unpriv, privs, desc)',    'whatever',    '    Extra privileges:        EXECUTE');
SELECT * FROM check_test(    function_privs_are(        'foo', ARRAY['integer', 'text'],        current_user, '{}'::text[], 'whatever'    ),    false,    'function_privs_are(func, args, unpriv, privs, desc)',    'whatever',    '    Extra privileges:        EXECUTE');
CREATE OR REPLACE FUNCTION public.function_with_a_moderate_signature(    anyelement, date, text[], boolean) RETURNS VOID LANGUAGE SQL AS '';
SELECT * FROM check_test(    function_privs_are(        'public', 'function_with_a_moderate_signature',        ARRAY['anyelement','date','text[]','boolean'],        current_user, ARRAY['EXECUTE'], 'whatever'    ),    true,    'long function signature',    'whatever',    '');
SELECT * FROM check_test(    language_privs_are( 'plpgsql', current_user, '{USAGE}', 'whatever' ),    true,    'language_privs_are(lang, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    language_privs_are( 'plpgsql', current_user, '{USAGE}' ),    true,    'language_privs_are(lang, role, privs, desc)',    'Role ' || quote_ident(current_user) || ' should be granted USAGE on language plpgsql',    '');
SELECT * FROM check_test(    language_privs_are( '__nonesuch', current_user, '{USAGE}', 'whatever' ),    false,    'language_privs_are(non-lang, role, privs, desc)',    'whatever',    '    Language __nonesuch does not exist');
SELECT * FROM check_test(    language_privs_are( 'plpgsql', '__noone', '{USAGE}', 'whatever' ),    false,    'language_privs_are(lang, non-role, privs, desc)',    'whatever',    '    Role __noone does not exist');
REVOKE USAGE ON LANGUAGE plpgsql FROM public;
SELECT * FROM check_test(    language_privs_are( 'plpgsql', '__someone_else', '{USAGE}', 'whatever' ),    false,    'language_privs_are(lang, ungranted, privs, desc)',    'whatever',    '    Missing privileges:        USAGE');
SELECT * FROM check_test(    language_privs_are( 'plpgsql', '__someone_else', '{}'::text[] ),    true,    'language_privs_are(lang, role, no privs)',    'Role __someone_else should be granted no privileges on language plpgsql',    '');
SELECT * FROM check_test(    schema_privs_are( current_schema(), current_user, ARRAY['CREATE', 'USAGE'], 'whatever' ),    true,    'schema_privs_are(schema, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    schema_privs_are( 'LOL', current_user, ARRAY['CREATE', 'USAGE'], 'whatever' ),    true,    'schema_privs_are(LOL, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    schema_privs_are( current_schema(), current_user, ARRAY['CREATE', 'USAGE'] ),    true,    'schema_privs_are(schema, role, privs, desc)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(ARRAY['CREATE', 'USAGE'], ', ') || ' on schema ' || current_schema(),    '');
SELECT * FROM check_test(    schema_privs_are( 'LOL', current_user, ARRAY['CREATE', 'USAGE'] ),    true,    'schema_privs_are(LOL, role, privs, desc)',    'Role ' || quote_ident(current_user) || ' should be granted '         || array_to_string(ARRAY['CREATE', 'USAGE'], ', ') || ' on schema "LOL"',    '');
SELECT * FROM check_test(    schema_privs_are( '__nonesuch', current_user, ARRAY['CREATE', 'USAGE'], 'whatever' ),    false,    'schema_privs_are(non-schema, role, privs, desc)',    'whatever',    '    Schema __nonesuch does not exist');
SELECT * FROM check_test(    schema_privs_are( current_schema(), '__noone', ARRAY['CREATE', 'USAGE'], 'whatever' ),    false,    'schema_privs_are(schema, non-role, privs, desc)',    'whatever',    '    Role __noone does not exist');
SELECT * FROM check_test(    schema_privs_are( current_schema(), '__someone_else', ARRAY['CREATE', 'USAGE'], 'whatever' ),    false,    'schema_privs_are(schema, ungranted, privs, desc)',    'whatever',    '    Missing privileges:        CREATE        USAGE');
SELECT * FROM check_test(    schema_privs_are(        current_schema(), current_user, ARRAY['CREATE'],        'whatever'    ),    false,    'schema_privs_are(schema, ungranted, privs, desc)',    'whatever',    '    Extra privileges:        USAGE');
SELECT * FROM check_test(    schema_privs_are( current_schema(), '__noone', '{}'::text[] ),    false,    'schema_privs_are(schema, non-role, no privs)',    'Role __noone should be granted no privileges on schema ' || current_schema(),    '    Role __noone does not exist');
SELECT * FROM check_test(    tablespace_privs_are( 'pg_default', current_user, '{CREATE}', 'whatever' ),    true,    'tablespace_privs_are(tablespace, role, privs, desc)',    'whatever',    '');
SELECT * FROM check_test(    tablespace_privs_are( 'pg_default', current_user, '{CREATE}' ),    true,    'tablespace_privs_are(tablespace, role, privs, desc)',    'Role ' || quote_ident(current_user) || ' should be granted CREATE on tablespace pg_default',    '');
SELECT * FROM check_test(    tablespace_privs_are( '__nonesuch', current_user, '{CREATE}', 'whatever' ),    false,    'tablespace_privs_are(non-tablespace, role, privs, desc)',    'whatever',    '    Tablespace __nonesuch does not exist');
SELECT * FROM check_test(    tablespace_privs_are( 'pg_default', '__noone', '{CREATE}', 'whatever' ),    false,    'tablespace_privs_are(tablespace, non-role, privs, desc)',    'whatever',    '    Role __noone does not exist');
REVOKE CREATE ON TABLESPACE pg_default FROM public;
SELECT * FROM check_test(    tablespace_privs_are( 'pg_default', '__someone_else', '{CREATE}', 'whatever' ),    false,    'tablespace_privs_are(tablespace, ungranted, privs, desc)',    'whatever',    '    Missing privileges:        CREATE');
SELECT * FROM check_test(    tablespace_privs_are( 'pg_default', '__someone_else', '{}'::text[] ),    true,    'tablespace_privs_are(tablespace, role, no privs)',    'Role __someone_else should be granted no privileges on tablespace pg_default',    '');
CREATE FUNCTION test_sequence() RETURNS SETOF TEXT AS $$DECLARE    allowed_privs TEXT[];
    test_privs    TEXT[];
    missing_privs TEXT[];
    tap           record;
    last_index    INTEGER;
BEGIN    IF pg_version_num() >= 90000 THEN        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', current_user, ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'sequence_privs_are(sch, seq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'LOL', 'ASeq', current_user, ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'sequence_privs_are(LOL, ASeq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ),            true,            'sequence_privs_are(sch, seq, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ')                || ' on sequence ha.someseq' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'LOL', 'ASeq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ),            true,            'sequence_privs_are(sch, seq, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ')                || ' on sequence "LOL"."ASeq"' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'someseq', current_user, ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'sequence_privs_are(seq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ASeq', current_user, ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'sequence_privs_are(ASeq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'someseq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ),            true,            'sequence_privs_are(seq, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ')                || ' on sequence someseq' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ASeq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ),            true,            'sequence_privs_are(seq, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ')                || ' on sequence "ASeq"' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                allowed_privs := ARRAY['USAGE', 'SELECT', 'UPDATE'];
        last_index    := array_upper(allowed_privs, 1);
        FOR i IN 1..last_index - 2 LOOP            test_privs := test_privs || allowed_privs[i];
        END LOOP;
        FOR i IN last_index - 1..last_index LOOP            missing_privs := missing_privs || allowed_privs[i];
        END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', current_user, test_privs, 'whatever' ),            false,            'sequence_privs_are(sch, seq, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'someseq', current_user, test_privs, 'whatever' ),            false,            'sequence_privs_are(seq, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', '__someone_else', ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'sequence_privs_are(sch, seq, other, privs, desc)',            'whatever',            '    Missing privileges:        ' || array_to_string(ARRAY['SELECT', 'UPDATE', 'USAGE'], E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                GRANT SELECT, UPDATE ON ha.someseq TO __someone_else;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', '__someone_else', ARRAY[                'SELECT', 'UPDATE'            ], 'whatever'),            true,            'sequence_privs_are(sch, seq, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'nonesuch', current_user, ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'sequence_privs_are(sch, seq, role, privs, desc)',            'whatever',            '    Sequence ha.nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', '__nonesuch', ARRAY[                'USAGE', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'sequence_privs_are(sch, seq, role, privs, desc)',            'whatever',            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'ha', 'someseq', '__nonesuch', '{}'::text[] ),            false,            'sequence_privs_are(sch, seq, role, no privs)',            'Role __nonesuch should be granted no privileges on sequence ha.someseq' ,            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            sequence_privs_are( 'someseq', '__nonesuch', '{}'::text[] ),            false,            'sequence_privs_are(seq, role, no privs)',            'Role __nonesuch should be granted no privileges on sequence someseq' ,            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    ELSE                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(sch, seq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(LOL, ASeq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(sch, seq, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(sch, seq, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(seq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(ASeq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(seq, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(seq, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(sch, seq, role, some privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(seq, role, some privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(sch, seq, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'sequence_privs_are(sch, seq, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(sch, seq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(sch, seq, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(sch, seq, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'sequence_privs_are(seq, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    END IF;
END;
$$ LANGUAGE PLPGSQL;
SELECT * FROM test_sequence();
CREATE FUNCTION test_anycols() RETURNS SETOF TEXT AS $$DECLARE    allowed_privs TEXT[];
    test_privs    TEXT[];
    missing_privs TEXT[];
    tap           record;
    last_index    INTEGER;
BEGIN    IF pg_version_num() >= 80400 THEN        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'any_column_privs_are(sch, tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ] ),            true,            'any_column_privs_are(sch, tab, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ')                || ' on any column in ha.sometab' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'sometab', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'any_column_privs_are(tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'sometab', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ] ),            true,            'any_column_privs_are(tab, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ')                || ' on any column in sometab' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                allowed_privs := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'];
        last_index    := array_upper(allowed_privs, 1);
        FOR i IN 1..last_index - 2 LOOP            test_privs := test_privs || allowed_privs[i];
        END LOOP;
        FOR i IN last_index - 1..last_index LOOP            missing_privs := missing_privs || allowed_privs[i];
        END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', current_user, test_privs, 'whatever' ),            false,            'any_column_privs_are(sch, tab, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'sometab', current_user, test_privs, 'whatever' ),            false,            'any_column_privs_are(tab, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', '__someone_else', ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'any_column_privs_are(sch, tab, other, privs, desc)',            'whatever',            '    Missing privileges:        ' || array_to_string(ARRAY['REFERENCES'], E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', '__someone_else', ARRAY[                'SELECT', 'INSERT', 'UPDATE'            ], 'whatever'),            true,            'any_column_privs_are(sch, tab, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'nonesuch', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'any_column_privs_are(sch, tab, role, privs, desc)',            'whatever',            '    Table ha.nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', '__nonesuch', ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'any_column_privs_are(sch, tab, role, privs, desc)',            'whatever',            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'ha', 'sometab', '__nonesuch', '{}'::text[] ),            false,            'any_column_privs_are(sch, tab, role, no privs)',            'Role __nonesuch should be granted no privileges on any column in ha.sometab' ,            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            any_column_privs_are( 'sometab', '__nonesuch', '{}'::text[] ),            false,            'any_column_privs_are(tab, role, no privs)',            'Role __nonesuch should be granted no privileges on any column in sometab' ,            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    ELSE                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'any_column_privs_are(sch, tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'any_column_privs_are(sch, tab, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'any_column_privs_are(tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'any_column_privs_are(tab, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(sch, tab, role, some privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(tab, role, some privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(sch, tab, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'any_column_privs_are(sch, tab, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(sch, tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(sch, tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(sch, tab, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'any_column_privs_are(tab, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    END IF;
END;
$$ LANGUAGE PLPGSQL;
SELECT * FROM test_anycols();
CREATE FUNCTION test_cols() RETURNS SETOF TEXT AS $$DECLARE    allowed_privs TEXT[];
    test_privs    TEXT[];
    missing_privs TEXT[];
    tap           record;
    last_index    INTEGER;
BEGIN    IF pg_version_num() >= 80400 THEN        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'column_privs_are(sch, tab, col, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'LOL', 'ATable', 'AColumn', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'column_privs_are(LOL, ATable, AColumn, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ] ),            true,            'column_privs_are(sch, tab, col, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ')                || ' on column ha.sometab.id' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'LOL', 'ATable', 'AColumn', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ] ),            true,            'column_privs_are(LOL, ATable, AColumn, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ')                || ' on column "LOL"."ATable"."AColumn"' ,            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'sometab', 'id', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'column_privs_are(tab, col, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ATable', 'AColumn', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            true,            'column_privs_are(tab, col, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'sometab', 'id', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ] ),            true,            'column_privs_are(tab, col, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ')                || ' on column sometab.id' ,                ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ATable', 'AColumn', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ] ),            true,            'column_privs_are(tab, col, role, privs)',            'Role ' || quote_ident(current_user) || ' should be granted '                || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ')                || ' on column "ATable"."AColumn"' ,                ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                allowed_privs := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'];
        last_index    := array_upper(allowed_privs, 1);
        FOR i IN 1..last_index - 2 LOOP            test_privs := test_privs || allowed_privs[i];
        END LOOP;
        FOR i IN last_index - 1..last_index LOOP            missing_privs := missing_privs || allowed_privs[i];
        END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', current_user, test_privs, 'whatever' ),            false,            'column_privs_are(sch, tab, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'sometab', 'id', current_user, test_privs, 'whatever' ),            false,            'column_privs_are(tab, role, some privs, desc)',            'whatever',            '    Extra privileges:        ' || array_to_string(missing_privs, E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', '__someone_else', ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'column_privs_are(sch, tab, other, privs, desc)',            'whatever',            '    Missing privileges:        ' || array_to_string(ARRAY['REFERENCES'], E'\n        ')        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                EXECUTE 'GRANT SELECT, INSERT, UPDATE (id) ON ha.sometab TO __someone_else;
';
';
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', '__someone_else', ARRAY[                'SELECT', 'INSERT', 'UPDATE'            ], 'whatever'),            true,            'column_privs_are(sch, tab, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'nonesuch', 'id', current_user, ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'column_privs_are(sch, tab, role, privs, desc)',            'whatever',            '    Table ha.nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', '__nonesuch', ARRAY[                'INSERT', 'REFERENCES', 'SELECT', 'UPDATE'            ], 'whatever' ),            false,            'column_privs_are(sch, tab, role, privs, desc)',            'whatever',            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            column_privs_are( 'ha', 'sometab', 'id', '__nonesuch', '{}'::text[] ),            false,            'column_privs_are(sch, tab, role, no privs)',            'Role __nonesuch should be granted no privileges on column ha.sometab.id' ,            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            column_privs_are( 'sometab', 'id', '__nonesuch', '{}'::text[] ),            false,            'column_privs_are(tab, role, no privs)',            'Role __nonesuch should be granted no privileges on column sometab.id' ,            '    Role __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    ELSE               FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(sch, tab, col, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
       FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(LOL, ATable, AColumn, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(sch, tab, col, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(LOL, ATable, AColumn, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(tab, col, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(tab, col, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(tab, col, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(tab, col, role, privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(sch, tab, role, some privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(tab, role, some privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(sch, tab, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'column_privs_are(sch, tab, other, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(sch, tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(sch, tab, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(sch, tab, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'column_privs_are(tab, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    END IF;
END;
$$ LANGUAGE PLPGSQL;
SELECT * FROM test_cols();
CREATE FUNCTION test_fdw() RETURNS SETOF TEXT AS $$DECLARE    tap record;
BEGIN    IF pg_version_num() >= 80400 THEN        EXECUTE 'CREATE FOREIGN DATA WRAPPER dummy;
';
';
        EXECUTE 'CREATE FOREIGN DATA WRAPPER "SomeFDW";
';
';
        FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'dummy', current_user, '{USAGE}', 'whatever' ),            true,            'fdw_privs_are(fdw, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'SomeFDW', current_user, '{USAGE}', 'whatever' ),            true,            'fdw_privs_are(SomeFDW, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'dummy', current_user, '{USAGE}' ),            true,            'fdw_privs_are(fdw, role, privs, desc)',            'Role ' || quote_ident(current_user) || ' should be granted USAGE on FDW dummy',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'SomeFDW', current_user, '{USAGE}' ),            true,            'fdw_privs_are(SomeFDW, role, privs, desc)',            'Role ' || quote_ident(current_user) || ' should be granted USAGE on FDW "SomeFDW"',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fdw_privs_are( '__nonesuch', current_user, '{USAGE}', 'whatever' ),            false,            'fdw_privs_are(non-fdw, role, privs, desc)',            'whatever',            '    FDW __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'dummy', '__noone', '{USAGE}', 'whatever' ),            false,            'fdw_privs_are(fdw, non-role, privs, desc)',            'whatever',            '    Role __noone does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'dummy', '__someone_else', '{USAGE}', 'whatever' ),            false,            'fdw_privs_are(fdw, ungranted, privs, desc)',            'whatever',            '    Missing privileges:        USAGE'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fdw_privs_are( 'dummy', '__someone_else', '{}'::text[] ),            true,            'fdw_privs_are(fdw, role, no privs)',            'Role __someone_else should be granted no privileges on FDW dummy',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    ELSE                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'fdw_privs_are(fdw, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'fdw_privs_are(SomeFDW, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'fdw_privs_are(fdw, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'fdw_privs_are(SomeFDW, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'fdw_privs_are(non-fdw, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'fdw_privs_are(fdw, non-role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'fdw_privs_are(fdw, ungranted, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'fdw_privs_are(fdw, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    END IF;
    RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM test_fdw();
CREATE FUNCTION test_server() RETURNS SETOF TEXT AS $$DECLARE    tap record;
BEGIN    IF pg_version_num() >= 80400 THEN        EXECUTE 'CREATE SERVER foo FOREIGN DATA WRAPPER dummy;
';
';
        EXECUTE 'CREATE SERVER "SomeServer" FOREIGN DATA WRAPPER "SomeFDW";
';
';
        FOR tap IN SELECT * FROM check_test(            server_privs_are( 'foo', current_user, '{USAGE}', 'whatever' ),            true,            'server_privs_are(server, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            server_privs_are( 'SomeServer', current_user, '{USAGE}', 'whatever' ),            true,            'server_privs_are(SomeServer, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            server_privs_are( 'foo', current_user, '{USAGE}' ),            true,            'server_privs_are(server, role, privs, desc)',            'Role ' || quote_ident(current_user) || ' should be granted USAGE on server foo',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            server_privs_are( 'SomeServer', current_user, '{USAGE}' ),            true,            'server_privs_are(SomeServer, role, privs, desc)',            'Role ' || quote_ident(current_user) || ' should be granted USAGE on server "SomeServer"',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            server_privs_are( '__nonesuch', current_user, '{USAGE}', 'whatever' ),            false,            'server_privs_are(non-server, role, privs, desc)',            'whatever',            '    Server __nonesuch does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            server_privs_are( 'foo', '__noone', '{USAGE}', 'whatever' ),            false,            'server_privs_are(server, non-role, privs, desc)',            'whatever',            '    Role __noone does not exist'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            server_privs_are( 'foo', '__someone_else', '{USAGE}', 'whatever' ),            false,            'server_privs_are(server, ungranted, privs, desc)',            'whatever',            '    Missing privileges:        USAGE'        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            server_privs_are( 'foo', '__someone_else', '{}'::text[] ),            true,            'server_privs_are(server, role, no privs)',            'Role __someone_else should be granted no privileges on server foo',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    ELSE                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'server_privs_are(server, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'server_privs_are(SomeServer, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'server_privs_are(server, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
        FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'server_privs_are(SomeServer, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'server_privs_are(non-server, role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'server_privs_are(server, non-role, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            fail('whatever'),            false,            'server_privs_are(server, ungranted, privs, desc)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
                FOR tap IN SELECT * FROM check_test(            pass('whatever'),            true,            'server_privs_are(server, role, no privs)',            'whatever',            ''        ) AS b LOOP RETURN NEXT tap.b;
 END LOOP;
 END LOOP;
    END IF;
    RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM test_server();
SELECT * FROM finish();
ROLLBACK;
